package com.nulldev.util.scripting.ScriptAPI.brainfuck;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

import com.nulldev.util.data.Arrays.arrays.FastLists;

public class BrainfuckEngine extends AbstractScriptEngine {
	private List<Bindings> bindings = FastLists.list();

	@Override
	public Object eval(final String script, final ScriptContext context) throws ScriptException {
		Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
		if (bindings == null)
			bindings = new SimpleBindings();
		for (final Bindings b : this.bindings) {
			bindings.putAll(b);
		}
		final BrainfuckInterpreter interpreter = new BrainfuckInterpreter(bindings.containsKey("cycles") ? (int) bindings.get("cycles") : 10000,
				bindings.containsKey("memory") ? (int) bindings.get("memory") : (1 << 15));
		try {
			return interpreter.process(script.toCharArray(), bindings.containsKey("input") ? (String) bindings.get("input") : "");
		} catch (BrainfuckInterpreter.BrainfuckException e) {
			throw new ScriptException(e);
		}
	}

	@Override
	public Object eval(final Reader reader, final ScriptContext context) throws ScriptException {
		final StringBuilder sb = new StringBuilder(128);
		try {
			int i;
			while ((i = reader.read()) != -1) {
				sb.append((char) i);
			}
		} catch (IOException e) {
			throw new ScriptException(e);
		}
		return eval(sb.toString(), context);
	}

	@Override
	public Bindings createBindings() {
		final Bindings b = new SimpleBindings();
		this.bindings.add(b);
		return b;
	}

	@Override
	public ScriptEngineFactory getFactory() {
		return BrainfuckFactory.INSTANCE;
	}
}
